<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.2">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"example.com","root":"/","scheme":"Muse","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="CPUCPU 是移动设备最重要的计算资源，设计糟糕的应用可能会造成 CPU 持续以高负载运行，一方面会导致用户使用过程遭遇卡顿；另一方面也会导致手机发热发烫，电量被快速消耗完，严重影响用户体验。 相关系统原理iOS 是基于 Apple Darwin 内核，由 kernel、XNU 和 Runtime 组成，XNU（X is not UNIX） 是 Darwin 的内核，一个混合内核，由 Mach">
<meta property="og:type" content="article">
<meta property="og:title" content="CPU &amp; 内存监控">
<meta property="og:url" content="http://example.com/2021/03/24/CPU%20&%20%E5%86%85%E5%AD%98%E7%9B%91%E6%8E%A7/index.html">
<meta property="og:site_name" content="Shi">
<meta property="og:description" content="CPUCPU 是移动设备最重要的计算资源，设计糟糕的应用可能会造成 CPU 持续以高负载运行，一方面会导致用户使用过程遭遇卡顿；另一方面也会导致手机发热发烫，电量被快速消耗完，严重影响用户体验。 相关系统原理iOS 是基于 Apple Darwin 内核，由 kernel、XNU 和 Runtime 组成，XNU（X is not UNIX） 是 Darwin 的内核，一个混合内核，由 Mach">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://raw.githubusercontent.com/shijianmei/blog_Images/main/CPU%26%E5%86%85%E5%AD%98%E7%9B%91%E6%8E%A7/image.png">
<meta property="article:published_time" content="2021-03-24T12:12:32.000Z">
<meta property="article:modified_time" content="2023-05-24T07:17:32.896Z">
<meta property="article:author" content="Shi">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://raw.githubusercontent.com/shijianmei/blog_Images/main/CPU%26%E5%86%85%E5%AD%98%E7%9B%91%E6%8E%A7/image.png">

<link rel="canonical" href="http://example.com/2021/03/24/CPU%20&%20%E5%86%85%E5%AD%98%E7%9B%91%E6%8E%A7/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>CPU & 内存监控 | Shi</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Shi</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/03/24/CPU%20&%20%E5%86%85%E5%AD%98%E7%9B%91%E6%8E%A7/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Shi">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Shi">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          CPU & 内存监控
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2021-03-24 20:12:32" itemprop="dateCreated datePublished" datetime="2021-03-24T20:12:32+08:00">2021-03-24</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/source/categories/%E6%80%A7%E8%83%BD/" itemprop="url" rel="index"><span itemprop="name">性能</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h2 id="CPU"><a href="#CPU" class="headerlink" title="CPU"></a>CPU</h2><p>CPU 是移动设备最重要的计算资源，设计糟糕的应用可能会造成 CPU 持续以高负载运行，一方面会导致用户使用过程遭遇卡顿；另一方面也会导致手机发热发烫，电量被快速消耗完，严重影响用户体验。</p>
<h3 id="相关系统原理"><a href="#相关系统原理" class="headerlink" title="相关系统原理"></a>相关系统原理</h3><p>iOS 是基于 Apple Darwin 内核，由 kernel、XNU 和 Runtime 组成，XNU（X is not UNIX） 是 Darwin 的内核，一个混合内核，由 Mach 微内核和 BSD 组成。Mach 内核是轻量级的平台，只能完成操作系统最基本的职责，如：进程和线程、虚拟内存管理、任务调度、进程通信和消息传递机制。其他的工作，如文件操作和设备访问，都是由 BSD 层实现。</p>
<p>事实上，Mach 并不能识别 UNIX 中的所有进程，而是采用一种稍微不同的方式，使用了比进程更轻量级的概念：<strong>任务（Task）</strong>。经典的 UNIX 采用了自上而下的方式：最基本的对象是进程，然后进一步划分为一个或多个线程；Mach 则采用了自底向上的方式：最基本的单元是线程，一个或多个线程包含在一个任务中。</p>
<blockquote>
<p><strong>线程：</strong>线程定义了 Mach 中最小的执行单元。线程表示的是底层的机器寄存器状态以及各种调度统计数据，其从设计上提供了调度所需要的大量信息。<br><strong>任务：</strong>任务是一种容器对象，虚拟内存空间和其他资源都是通过这个容器对象管理的。这些资源包括设备和其他句柄。资源进一步被抽象为端口。因此，资源的共享实际上相当于允许对对应端口进行访问。<br>严格来说，Mach 的任务并不是其它操作系统中所谓的进程，因为 Mach 作为一个微内核的操作系统，并没有提供“进程”的逻辑，而只提供了最基本的实现。在 BSD 模型中，这两个概念有一对一的简单映射，每个 BSD 进程（即 OS X 进程）都在底层关联了一个 Mach 任务对象。实现这种映射的方法是指定一个透明的指针 <code>bsd_info</code>，Mach 对 <code>bsd_info</code> 完全无知。Mach 将内核也用任务表示（全局范围称为 <code>kernel_task</code>），尽管该任务没有对应的 PID，但可以想象 PID 为 0。</p>
</blockquote>
<p>下图所示为权威著作《OS X Internal: A System Approach》中提供的 Mach OS X 中进程子系统组成的概念图。与 Mac OS X 类似，iOS 的线程技术也是基于 Mach 线程技术实现的。<br><img src="https://raw.githubusercontent.com/shijianmei/blog_Images/main/CPU%26%E5%86%85%E5%AD%98%E7%9B%91%E6%8E%A7/image.png"></p>
<p> Mach 层中的 <code>thread_basic_info</code> 结构体的定义：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">struct</span> <span class="title class_">thread_basic_info</span> &#123;</span><br><span class="line">        <span class="type">time_value_t</span>    user_time;      <span class="comment">// 用户运行时长</span></span><br><span class="line">        <span class="type">time_value_t</span>    system_time;    <span class="comment">// 系统运行时长</span></span><br><span class="line">        <span class="type">integer_t</span>       cpu_usage;      <span class="comment">// CPU 使用率</span></span><br><span class="line">        <span class="type">policy_t</span>        policy;         <span class="comment">// 调度策略</span></span><br><span class="line">        <span class="type">integer_t</span>       run_state;      <span class="comment">// 运行状态</span></span><br><span class="line">        <span class="type">integer_t</span>       flags;          <span class="comment">// 各种标记</span></span><br><span class="line">        <span class="type">integer_t</span>       suspend_count;  <span class="comment">// 暂停线程的计数</span></span><br><span class="line">        <span class="type">integer_t</span>       sleep_time;     <span class="comment">// 休眠时间</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="APP-的-CPU-占用率"><a href="#APP-的-CPU-占用率" class="headerlink" title="APP 的 CPU 占用率"></a>APP 的 CPU 占用率</h3><p>对于app使用率的获取，网上的方案还是比较统一的。</p>
<ol>
<li>使用task_threads函数，获取当前App行程中所有的线程列表。</li>
<li>对于第一步中获取的线程列表进行遍历，通过thread_info函数获取每一个非闲置线程的cpu使用率，进行相加。</li>
<li>使用vm_deallocate函数释放资源。<br>如下所示为 <strong>CPU 占用率</strong> 的代码实现：</li>
</ol>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">+ (CGFloat)cpuUsageForApp &#123;</span><br><span class="line">    <span class="type">kern_return_t</span> kr;</span><br><span class="line">    <span class="type">thread_array_t</span>         thread_list;</span><br><span class="line">    <span class="type">mach_msg_type_number_t</span> thread_count;</span><br><span class="line">    <span class="type">thread_info_data_t</span>     thinfo;</span><br><span class="line">    <span class="type">mach_msg_type_number_t</span> thread_info_count;</span><br><span class="line">    <span class="type">thread_basic_info_t</span> basic_info_th;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// get threads in the task</span></span><br><span class="line">    <span class="comment">//  获取当前进程中 线程列表</span></span><br><span class="line">    kr = <span class="built_in">task_threads</span>(<span class="built_in">mach_task_self</span>(), &amp;thread_list, &amp;thread_count);</span><br><span class="line">    <span class="keyword">if</span> (kr != KERN_SUCCESS)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="type">float</span> tot_cpu = <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt; thread_count; j++) &#123;</span><br><span class="line">        thread_info_count = THREAD_INFO_MAX;</span><br><span class="line">        <span class="comment">//获取每一个线程信息</span></span><br><span class="line">        kr = <span class="built_in">thread_info</span>(thread_list[j], THREAD_BASIC_INFO,</span><br><span class="line">                         (<span class="type">thread_info_t</span>)thinfo, &amp;thread_info_count);</span><br><span class="line">        <span class="keyword">if</span> (kr != KERN_SUCCESS)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">        </span><br><span class="line">        basic_info_th = (<span class="type">thread_basic_info_t</span>)thinfo;</span><br><span class="line">        <span class="keyword">if</span> (!(basic_info_th-&gt;flags &amp; TH_FLAGS_IDLE)) &#123;</span><br><span class="line">            <span class="comment">// cpu_usage : Scaled cpu usage percentage. The scale factor is TH_USAGE_SCALE.</span></span><br><span class="line">            <span class="comment">//宏定义TH_USAGE_SCALE返回CPU处理总频率：</span></span><br><span class="line">            tot_cpu += basic_info_th-&gt;cpu_usage / (<span class="type">float</span>)TH_USAGE_SCALE;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">    &#125; <span class="comment">// for each thread</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 注意方法最后要调用 vm_deallocate，防止出现内存泄漏</span></span><br><span class="line">    kr = <span class="built_in">vm_deallocate</span>(<span class="built_in">mach_task_self</span>(), (<span class="type">vm_offset_t</span>)thread_list, thread_count * <span class="built_in">sizeof</span>(<span class="type">thread_t</span>));</span><br><span class="line">    <span class="built_in">assert</span>(kr == KERN_SUCCESS);</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> tot_cpu;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Memory"><a href="#Memory" class="headerlink" title="Memory"></a>Memory</h2><h3 id="相关系统原理-1"><a href="#相关系统原理-1" class="headerlink" title="相关系统原理"></a>相关系统原理</h3><p>内存是有限且系统共享的资源，一个程序占用越多，系统和其他程序所能用的就越少。程序启动前都需要先加载到内存中，并且在程序运行过程中的数据操作也会占用一定的内存资源。减少内存占用也能同时减少其对 CPU 时间维度上的消耗，从而使不仅使 App 以及整个系统也都能表现的更好。</p>
<p>MacOS 和 iOS 都采用了虚拟内存技术来突破物理内存的大小限制，每个进程都有一段由多个大小相同的页（Page）所构成的逻辑地址空间。处理器和内存管理单元（MMU，Memory Management Unit）维护着由逻辑地址到物理地址的 <strong>页面映射表</strong>（简称 <strong>页表</strong>），当程序访问逻辑内存地址时，由 MMU 根据页表将逻辑地址转换为真实的物理地址。在早期的苹果设备中，每个页的大小为 4KB；基于 A7 和 A8 处理器的系统为 64 位程序提供了 16KB 的虚拟内存分页和 4KB 的物理内存分页；在 A9 之后，虚拟内存和物理内存的分页大小都达到了 16KB。</p>
<p>虚拟内存分页（Virtual Page，VP）有两种类型：</p>
<ol>
<li>Clean：指能够被系统清理出内存且在需要时能重新加载的数据，包括：<ol>
<li>内存映射文件</li>
<li>Frameworks 中的 __DATA_CONST 部分</li>
<li>应用的二进制可执行文件</li>
</ol>
</li>
<li>Dirty：指不能被系统回收的内存占用，包括：<ol>
<li>所有堆上的对象</li>
<li>图片解码缓冲数据</li>
<li>Framework 中的 <strong>DATA 和</strong>DATA_DIRTY 部分<br>由于内存容量和读写寿命的限制，iOS 上没有 Disk Swap 机制，取而代之使用 <strong>Compressed Memory</strong> 技术。 Disk Swap 是指在 macOS 以及一些其他桌面操作系统中，当内存可用资源紧张时，系统将内存中的内容写入磁盘中的backing store（Swapping out），并且在需要访问时从磁盘中再读入 RAM（Swapping in）。与大多数 UNIX 系统不同的是，macOS 没有预先分配磁盘中的一部分作为 backing store，而是利用引导分区所有可用的磁盘空间。</li>
</ol>
</li>
</ol>
<p>苹果最初只是公开了从 OS X Mavericks 开始使用 Compressed Memory 技术，但 iOS 系统也从 iOS 7 开始悄悄地使用。</p>
<p>Compressed Memory 技术在内存紧张时能够将最近使用过的内存占用压缩至原有大小的一半以下，并且能够在需要时解压复用。它在节省内存的同时提高了系统的响应速度，其特点可以归结为：</p>
<ul>
<li>减少了不活跃内存占用</li>
<li>改善电源效率，通过压缩减少磁盘 IO 带来的损耗</li>
<li>压缩/解压非常快，能够尽可能减少 CPU 的时间开销</li>
<li>支持多核操作<br>本质上，Compressed Memory 也是 Dirty Memory。因此，<strong>memory footprint = dirty size + compressed size</strong>，这也是我们需要并且能够尝试去减少的内存占用。</li>
</ul>
<h3 id="App-使用的内存"><a href="#App-使用的内存" class="headerlink" title="App 使用的内存"></a>App 使用的内存</h3><p>mach_task_basic_info 结构体存储了 Mach task 的内存使用信息，其中 resident_size 就是应用使用的物理内存大小，virtual_size 是虚拟内存大小。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> MACH_TASK_BASIC_INFO     20         <span class="comment">/* always 64-bit basic info */</span></span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">mach_task_basic_info</span> &#123;</span><br><span class="line">        <span class="type">mach_vm_size_t</span>  virtual_size;       <span class="comment">/* virtual memory size (bytes) */</span></span><br><span class="line">        <span class="type">mach_vm_size_t</span>  resident_size;      <span class="comment">/* resident memory size (bytes) */</span></span><br><span class="line">        <span class="type">mach_vm_size_t</span>  resident_size_max;  <span class="comment">/* maximum resident memory size (bytes) */</span></span><br><span class="line">        <span class="type">time_value_t</span>    user_time;          <span class="comment">/* total user run time for</span></span><br><span class="line"><span class="comment">                                               terminated threads */</span></span><br><span class="line">        <span class="type">time_value_t</span>    system_time;        <span class="comment">/* total system run time for</span></span><br><span class="line"><span class="comment">                                               terminated threads */</span></span><br><span class="line">        <span class="type">policy_t</span>        policy;             <span class="comment">/* default policy for new threads */</span></span><br><span class="line">        <span class="type">integer_t</span>       suspend_count;      <span class="comment">/* suspend count for task */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>task_info API 根据指定的 flavor 类型返回 target_task 的信息。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">kern_return_t</span> <span class="title">task_info</span></span></span><br><span class="line"><span class="function"><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">    <span class="type">task_name_t</span> target_task,</span></span></span><br><span class="line"><span class="params"><span class="function">    <span class="type">task_flavor_t</span> flavor,</span></span></span><br><span class="line"><span class="params"><span class="function">    <span class="type">task_info_t</span> task_info_out,</span></span></span><br><span class="line"><span class="params"><span class="function">    <span class="type">mach_msg_type_number_t</span> *task_info_outCnt</span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>;</span><br></pre></td></tr></table></figure>
<p>于是得到获取当前 App Memory 的使用情况</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">- (NSUInteger)getResidentMemory</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">struct</span> <span class="title class_">mach_task_basic_info</span> info;</span><br><span class="line">    <span class="type">mach_msg_type_number_t</span> count = MACH_TASK_BASIC_INFO_COUNT;</span><br><span class="line">    <span class="type">int</span> r = <span class="built_in">task_info</span>(<span class="built_in">mach_task_self</span>(), MACH_TASK_BASIC_INFO, (<span class="type">task_info_t</span>)&amp; info, &amp; count);</span><br><span class="line">    <span class="keyword">if</span> (r == KERN_SUCCESS)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> info.resident_size;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>将上述代码采集到的 App RAM 的使用值与 Xcode 的 Debug Gauges 的 memory 对比，会发现代码会与 Debug Gauges 显示的值存在差异，有时甚至会差几百 MB，那么究竟怎样才能获取到应用使用的真实内存值呢？<br>我们先来看看 WebKit 源码中是怎样使用的，在 <a target="_blank" rel="noopener" href="https://github.com/WebKit/webkit/blob/52bc6f0a96a062cb0eb76e9a81497183dc87c268/Source/WTF/wtf/cocoa/MemoryFootprintCocoa.cpp">MemoryFootprintCocoa.cpp</a> 文件中，代码如下：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">size_t</span> <span class="title">memoryFootprint</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">task_vm_info_data_t</span> vmInfo;</span><br><span class="line">    <span class="type">mach_msg_type_number_t</span> count = TASK_VM_INFO_COUNT;</span><br><span class="line">    <span class="type">kern_return_t</span> result = <span class="built_in">task_info</span>(<span class="built_in">mach_task_self</span>(), TASK_VM_INFO, (<span class="type">task_info_t</span>) &amp;vmInfo, &amp;count);</span><br><span class="line">    <span class="keyword">if</span> (result != KERN_SUCCESS)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">static_cast</span>&lt;<span class="type">size_t</span>&gt;(vmInfo.phys_footprint);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>可以看到代码使用的不是 resident_size，而是 phys_footprint，phys_footprint 同样是 task_info 的成员变量。<br>当我们将获取内存的实现从 resident_size 换成 phys_footprint 时，于是代码获取的内存值就和 Xcode Debug Gauges 一致了。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">- (NSUInteger)getApplicationUsedMemory</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">struct</span> <span class="title class_">mach_task_basic_info</span> info;</span><br><span class="line">    <span class="type">mach_msg_type_number_t</span> count = MACH_TASK_BASIC_INFO_COUNT;</span><br><span class="line">    <span class="type">int</span> r = <span class="built_in">task_info</span>(<span class="built_in">mach_task_self</span>(), MACH_TASK_BASIC_INFO, (<span class="type">task_info_t</span>)&amp; info, &amp; count);</span><br><span class="line">    <span class="keyword">if</span> (r == KERN_SUCCESS)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> info.phys_footprint;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="获取设备总内存："><a href="#获取设备总内存：" class="headerlink" title="获取设备总内存："></a>获取设备总内存：</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">+ (NSUInteger)totalMemoryForDevice&#123;</span><br><span class="line">    <span class="keyword">return</span> [NSProcessInfo processInfo].physicalMemory/<span class="number">1024</span>/<span class="number">1024</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://github.com/didi/DoKit">DoKit</a><br><a target="_blank" rel="noopener" href="https://github.com/Tencent/GT">GT</a><br><a target="_blank" rel="noopener" href="https://github.com/Shmoopi/iOS-System-Services">iOS-System-Services</a><br><a target="_blank" rel="noopener" href="https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/kern_memorystatus.c">kern_memorystatus</a><br><a target="_blank" rel="noopener" href="https://www.infoq.cn/article/netease-ios-sdk-neteaseapm-technology-share/">NeteaseAPM iOS SDK</a><a target="_blank" rel="noopener" href="https://github.com/zenny-chen/CPU-Dasher-for-iOS">CPU-Dasher-for-iOS</a><br><a target="_blank" rel="noopener" href="https://github.com/everettjf/Yolo/blob/master/HookCppInitilizers/hook_cpp_init.mm">HookCppInitilizers</a><br><a target="_blank" rel="noopener" href="https://everettjf.github.io/2017/01/06/a-method-of-hook-objective-c-load/">a-method-of-hook-objective-c-load</a><br><a target="_blank" rel="noopener" href="https://github.com/maniackk/TimeProfiler/tree/master">TimeProfiler</a><br><a target="_blank" rel="noopener" href="https://github.com/tripleCC/Laboratory/blob/5c084263d79973805649b89d166b50751045e937/AppleSources/objc4-750/runtime/objc-file.mm#L32-L47">objc-file.mm</a></p>

    </div>

    
    
    

      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/04/26/Git%E4%B8%8D%E5%B8%B8%E7%94%A8%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/" rel="prev" title="Git不常用解决方案">
      <i class="fa fa-chevron-left"></i> Git不常用解决方案
    </a></div>
      <div class="post-nav-item">
    <a href="/2021/09/18/%E5%8D%A1%E9%A1%BF%E7%9B%91%E6%8E%A7/" rel="next" title="卡顿监控">
      卡顿监控 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#CPU"><span class="nav-number">1.</span> <span class="nav-text">CPU</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%9B%B8%E5%85%B3%E7%B3%BB%E7%BB%9F%E5%8E%9F%E7%90%86"><span class="nav-number">1.1.</span> <span class="nav-text">相关系统原理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#APP-%E7%9A%84-CPU-%E5%8D%A0%E7%94%A8%E7%8E%87"><span class="nav-number">1.2.</span> <span class="nav-text">APP 的 CPU 占用率</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Memory"><span class="nav-number">2.</span> <span class="nav-text">Memory</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%9B%B8%E5%85%B3%E7%B3%BB%E7%BB%9F%E5%8E%9F%E7%90%86-1"><span class="nav-number">2.1.</span> <span class="nav-text">相关系统原理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#App-%E4%BD%BF%E7%94%A8%E7%9A%84%E5%86%85%E5%AD%98"><span class="nav-number">2.2.</span> <span class="nav-text">App 使用的内存</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%8E%B7%E5%8F%96%E8%AE%BE%E5%A4%87%E6%80%BB%E5%86%85%E5%AD%98%EF%BC%9A"><span class="nav-number">2.3.</span> <span class="nav-text">获取设备总内存：</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">Shi</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">9</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">5</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/shijianmei" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;shijianmei" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        <!--

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Shi</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://muse.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>
-->

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/muse.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

</body>
</html>
